package com.itheima.sfbx.insurance.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.itheima.sfbx.framework.commons.exception.ProjectException;
import com.itheima.sfbx.framework.commons.utils.BeanConv;
import com.itheima.sfbx.framework.commons.utils.EmptyUtil;
import com.itheima.sfbx.framework.commons.utils.ExceptionsUtil;
import com.itheima.sfbx.framework.mybatisplus.basic.BasePojo;
import com.itheima.sfbx.insurance.constant.InsurancePlanCacheConstant;
import com.itheima.sfbx.insurance.dto.InsurancePlanVO;
import com.itheima.sfbx.insurance.dto.PlanEarningsVO;
import com.itheima.sfbx.insurance.dto.PlanSafeguardVO;
import com.itheima.sfbx.insurance.enums.InsurancePlanEnum;
import com.itheima.sfbx.insurance.mapper.InsurancePlanMapper;
import com.itheima.sfbx.insurance.pojo.InsurancePlan;
import com.itheima.sfbx.insurance.pojo.PlanEarnings;
import com.itheima.sfbx.insurance.pojo.PlanSafeguard;
import com.itheima.sfbx.insurance.service.IInsurancePlanService;
import com.itheima.sfbx.insurance.service.IPlanEarningsService;
import com.itheima.sfbx.insurance.service.IPlanSafeguardService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Description：保险方案服务实现类
 */
@Slf4j
@Service
public class InsurancePlanServiceImpl extends ServiceImpl<InsurancePlanMapper, InsurancePlan> implements IInsurancePlanService {

    @Autowired
    IPlanSafeguardService planSafeguardService;

    @Autowired
    IPlanEarningsService planEarningsService;

    @Autowired
    IdentifierGenerator identifierGenerator;


    /***
     * @description 保险方案多条件组合
     * @param insurancePlanVO 保险方案
     * @return QueryWrapper查询条件
     */
    private QueryWrapper<InsurancePlan> queryWrapper(InsurancePlanVO insurancePlanVO) {
        QueryWrapper<InsurancePlan> queryWrapper = new QueryWrapper<>();
        //保险商品id查询
        if (!EmptyUtil.isNullOrEmpty(insurancePlanVO.getInsuranceId())) {
            queryWrapper.lambda().eq(InsurancePlan::getInsuranceId, insurancePlanVO.getInsuranceId());
        }
        //保险商品ids列表查询
        if (!EmptyUtil.isNullOrEmpty(insurancePlanVO.getInsuranceIds())) {
            queryWrapper.lambda().in(InsurancePlan::getInsuranceId, insurancePlanVO.getInsuranceIds());
        }
        //保险计划名称查询
        if (!EmptyUtil.isNullOrEmpty(insurancePlanVO.getPalnName())) {
            queryWrapper.lambda().eq(InsurancePlan::getPalnName, insurancePlanVO.getPalnName());
        }
        //默认定价查询
        if (!EmptyUtil.isNullOrEmpty(insurancePlanVO.getPrice())) {
            queryWrapper.lambda().eq(InsurancePlan::getPrice, insurancePlanVO.getPrice());
        }
        //默认定价单位：y/d,y/m,y/y查询
        if (!EmptyUtil.isNullOrEmpty(insurancePlanVO.getPriceUnit())) {
            queryWrapper.lambda().eq(InsurancePlan::getPriceUnit, insurancePlanVO.getPriceUnit());
        }
        //排序查询
        if (!EmptyUtil.isNullOrEmpty(insurancePlanVO.getSortNo())) {
            queryWrapper.lambda().eq(InsurancePlan::getSortNo, insurancePlanVO.getSortNo());
        }
        //状态查询
        if (!EmptyUtil.isNullOrEmpty(insurancePlanVO.getDataState())) {
            queryWrapper.lambda().eq(InsurancePlan::getDataState, insurancePlanVO.getDataState());
        }
        //按创建时间降序
        queryWrapper.lambda().orderByDesc(InsurancePlan::getCreateTime);
        return queryWrapper;
    }

    @Override
    @Cacheable(value = InsurancePlanCacheConstant.PAGE, key = "#pageNum+'-'+#pageSize+'-'+#insurancePlanVO.hashCode()")
    public Page<InsurancePlanVO> findPage(InsurancePlanVO insurancePlanVO, int pageNum, int pageSize) {
        try {
            //构建分页对象
            Page<InsurancePlan> InsurancePlanPage = new Page<>(pageNum, pageSize);
            //构建查询条件
            QueryWrapper<InsurancePlan> queryWrapper = queryWrapper(insurancePlanVO);
            //执行分页查询
            Page<InsurancePlanVO> insurancePlanVOPage = BeanConv.toPage(page(InsurancePlanPage, queryWrapper), InsurancePlanVO.class);
            if (!EmptyUtil.isNullOrEmpty(insurancePlanVOPage.getRecords())) {
                //补全方案保障项、给付计划
                Set<Long> planIds = insurancePlanVOPage.getRecords().stream().map(InsurancePlanVO::getId).collect(Collectors.toSet());
                //保障项
                List<PlanSafeguardVO> planSafeguardVOs = planSafeguardService.findInPlanId(planIds);
                List<PlanSafeguardVO> planSafeguardVOsHandler = Lists.newArrayList();
                //给付计划
                List<PlanEarningsVO> planEarningsVOs = planEarningsService.findInPlanId(planIds);
                insurancePlanVOPage.getRecords().forEach(n -> {
                    planSafeguardVOs.forEach(i -> {
                        if (n.getId().equals(i.getPlanId())) {
                            planSafeguardVOsHandler.add(i);
                        }
                    });
                    n.setPlanSafeguardVOs(planSafeguardVOsHandler);
                    planEarningsVOs.forEach(j -> {
                        if (n.getId().equals(j.getPalnId())) {
                            n.setPlanEarningsVO(j);
                        }
                    });
                });
            }
            //返回结果
            return insurancePlanVOPage;
        } catch (Exception e) {
            log.error("保险方案分页查询异常：{}", ExceptionsUtil.getStackTraceAsString(e));
            throw new ProjectException(InsurancePlanEnum.PAGE_FAIL);
        }
    }

    @Override
    @Cacheable(value = InsurancePlanCacheConstant.BASIC, key = "#insurancePlanId")
    public InsurancePlanVO findByIdAndInsuranceId(Long insurancePlanId, Long insuranceId) {
        try {
            //执行查询
            QueryWrapper<InsurancePlan> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(InsurancePlan::getId, insurancePlanId).eq(InsurancePlan::getInsuranceId, insuranceId);
            InsurancePlanVO insurancePlanVO = BeanConv.toBean(getOne(queryWrapper), InsurancePlanVO.class);
            //方案保障项
            List<PlanSafeguardVO> planSafeguardVOs = planSafeguardService.findByPlanId(insurancePlanVO.getId());
            insurancePlanVO.setPlanSafeguardVOs(planSafeguardVOs);
            //方案给付计划
            PlanEarningsVO planEarningsVO = planEarningsService.findByPlanId(insurancePlanVO.getId());
            insurancePlanVO.setPlanEarningsVO(planEarningsVO);
            return insurancePlanVO;
        } catch (Exception e) {
            log.error("保险方案单条查询异常：{}", ExceptionsUtil.getStackTraceAsString(e));
            throw new ProjectException(InsurancePlanEnum.FIND_ONE_FAIL);
        }
    }

    @Override
    @Transactional
    @Caching(evict = {@CacheEvict(value = InsurancePlanCacheConstant.PAGE, allEntries = true),
            @CacheEvict(value = InsurancePlanCacheConstant.LIST, allEntries = true)})
    public Boolean save(List<InsurancePlanVO> insurancePlanVOs) {
        try {
            //先设置flag
            boolean flag = false;
            //1、批量保存方案
            //1.1、设置每个方案编号
            //identifierGenerator --> 是唯一id生成器
            insurancePlanVOs.forEach(insurancePlanVO -> {
                insurancePlanVO.setPlanNo(identifierGenerator.nextId(insurancePlanVO).longValue());
            });
            //1.2、批量保存
            //转成InsurancePlan对象
            List<InsurancePlan> insurancePlanList = BeanConv.toBeanList(insurancePlanVOs, InsurancePlan.class);
            //进行批量保存;mp会自动填充方案的id
            flag = saveBatch(insurancePlanList);

            //将方案的编号与方案id对应起来; map<方案编号, 放哪id> 方案根据方案编号获取方案id
            //  null 不能为map的key  --> 直接大debug,键ctrl + f  进行ai, 然后自己定位即可
            Map<Long, Long> planNoAndIdMap = insurancePlanList.stream()
                    .collect(Collectors.toMap(InsurancePlan::getPlanNo, InsurancePlan::getId));

            //2、批量保存方案保障项
            //遍历每一个方案, 并获取方案对应的保障想  insurancePlanVO --> 是不存在id, 但是存在编号
            insurancePlanVOs.forEach(insurancePlanVO -> {
                //判断保障项是否存在
                List<PlanSafeguardVO> planSafeguardVOs = insurancePlanVO.getPlanSafeguardVOs();
                if (CollectionUtil.isNotEmpty(planSafeguardVOs)) {
                    //2.1、对每个保障项设置方案id
                    planSafeguardVOs.forEach(planSafeguardVO -> {
                        planSafeguardVO.setPlanId(planNoAndIdMap.get(insurancePlanVO.getPlanNo()));
                    });
                    //2.2、批量保存每个方案中的多个保障项
                    //转换成PlanSafeguard对象
                    List<PlanSafeguard> beanList = BeanConv.toBeanList(planSafeguardVOs, PlanSafeguard.class);
                    //进行批量保存
                    planSafeguardService.saveBatch(beanList);
                }
            });
            //3、批量保存给付计划
            insurancePlanVOs.forEach(insurancePlanVO -> {
                //只有养老、储蓄类的保险才有给付计划 --> 极端判断, 给付计划是否为null 只有一个
                if (insurancePlanVO.getPlanEarningsVO() != null) {
                    //3.1、对给付计划设置方案id
                    insurancePlanVO.getPlanEarningsVO().setPalnId(planNoAndIdMap.get(insurancePlanVO.getPlanNo()));
                    //3.2、保存给付计划
                    //对象转换
                    PlanEarnings planEarnings = BeanConv.toBean(insurancePlanVO.getPlanEarningsVO(), PlanEarnings.class);
                    planEarningsService.save(planEarnings); // 严格按照,与数据库对应的实体类,进行书写就可以了
//                    planEarningsService.save(insurancePlanVO.getPlanEarningsVO()); // --> 疑惑, 为什么也行
                }
            });
            return flag;
        } catch (Exception e) {
            log.error("保存保险方案异常：{}", ExceptionsUtil.getStackTraceAsString(e));
            e.printStackTrace();
            throw new ProjectException(InsurancePlanEnum.SAVE_FAIL);
        }
    }

    @Override
    @Transactional
    @Caching(evict = {@CacheEvict(value = InsurancePlanCacheConstant.PAGE, allEntries = true),
            @CacheEvict(value = InsurancePlanCacheConstant.LIST, allEntries = true)})
    public Boolean update(List<InsurancePlanVO> insurancePlanVOs) {
        try {
            //查询原产品方案 --> 这查询已经到软件内存中了  --> 目的是获取原产品方案的ids  --> 只是做一个备用
            QueryWrapper<InsurancePlan> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(InsurancePlan::getInsuranceId, insurancePlanVOs.get(0).getInsuranceId());
            List<InsurancePlan> insurancePlanList = list(queryWrapper);
            if (EmptyUtil.isNullOrEmpty(insurancePlanList)){
                throw new RuntimeException("查询原方案失败");
            }

            //删除原产品方案
            List<Long> ids = insurancePlanList.stream().map(InsurancePlan::getId).collect(Collectors.toList());
            boolean flag = removeByIds(ids);
            if (!flag){
                throw new RuntimeException("删除原方案失败");
            }
            //删除原产品方案保障项
             flag = planSafeguardService.deleteInPlanIds(ids);
            if (!flag){
                throw new RuntimeException("删除原方案保障项失败");
            }
            //删除原产品方案给付计划
            flag = planEarningsService.deleteInPlanIds(ids);
            //可能是不存在, 就不进行判断了
            //清空产品方案ID
            insurancePlanVOs.forEach(n->n.setId(null));
            //再次重新保存
            return this.save(insurancePlanVOs);
        } catch (Exception e) {
            log.error("修改保险方案异常：{}", ExceptionsUtil.getStackTraceAsString(e));
            throw new ProjectException(InsurancePlanEnum.UPDATE_FAIL);
        }
    }

    @Override
    @Transactional
    @Caching(evict = {@CacheEvict(value = InsurancePlanCacheConstant.PAGE, allEntries = true),
            @CacheEvict(value = InsurancePlanCacheConstant.LIST, allEntries = true),
            @CacheEvict(value = InsurancePlanCacheConstant.BASIC, allEntries = true)})
    public Boolean delete(String[] checkedIds) {
        try {
            List<Long> idsLong = Arrays.asList(checkedIds)
                    .stream().map(Long::new).collect(Collectors.toList());
            boolean flag = removeByIds(idsLong);
            if (!flag) {
                throw new RuntimeException("删除保险方案失败");
            }
            flag = planSafeguardService.deleteInPlanId(idsLong);
            if (!flag) {
                throw new RuntimeException("删除保险方案保障项失败");
            }
            flag = planEarningsService.deleteInPlanId(idsLong);
            if (!flag) {
                throw new RuntimeException("删除保险方案给付计划失败");
            }
            return flag;
        } catch (Exception e) {
            log.error("删除保险方案异常：{}", ExceptionsUtil.getStackTraceAsString(e));
            throw new ProjectException(InsurancePlanEnum.DEL_FAIL);
        }
    }

    @Override
    @Cacheable(value = InsurancePlanCacheConstant.LIST, key = "#insurancePlanVO.hashCode()")
    public List<InsurancePlanVO> findList(InsurancePlanVO insurancePlanVO) {
        try {
            //构建查询条件
            QueryWrapper<InsurancePlan> queryWrapper = queryWrapper(insurancePlanVO);
            //执行列表查询
            List<InsurancePlanVO> insurancePlanVOs = BeanConv.toBeanList(list(queryWrapper), InsurancePlanVO.class);
            if (!EmptyUtil.isNullOrEmpty(insurancePlanVOs)) {
                //补全方案保障项、给付计划
                Set<Long> planIds = insurancePlanVOs.stream().map(InsurancePlanVO::getId).collect(Collectors.toSet());
                //保障项
                List<PlanSafeguardVO> planSafeguardVOs = planSafeguardService.findInPlanId(planIds);
                //给付计划
                List<PlanEarningsVO> planEarningsVOs = planEarningsService.findInPlanId(planIds);
                insurancePlanVOs.forEach(n -> {
                    List<PlanSafeguardVO> planSafeguardVOsHandler = Lists.newArrayList();
                    planSafeguardVOs.forEach(i -> {
                        if (n.getId().equals(i.getPlanId())) {
                            planSafeguardVOsHandler.add(i);
                        }
                    });
                    n.setPlanSafeguardVOs(planSafeguardVOsHandler);
                    planEarningsVOs.forEach(j -> {
                        if (n.getId().equals(j.getPalnId())) {
                            n.setPlanEarningsVO(j);
                        }
                    });
                });
            }
            return insurancePlanVOs;
        } catch (Exception e) {
            log.error("保险方案列表查询异常：{}", ExceptionsUtil.getStackTraceAsString(e));
            throw new ProjectException(InsurancePlanEnum.LIST_FAIL);
        }
    }

}
